package org.black.phoneUtility.sms.schedule.widget;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.black.phoneUtility.R;
import org.black.phoneUtility.sms.schedule.provider.SmsScheduleContract;
import org.black.phoneUtility.sms.schedule.service.SmsScheduleService;
import org.black.phoneUtility.sms.schedule.service.exception.EndDateTimeHasExpiredException;
import org.black.phoneUtility.sms.schedule.service.exception.NextScheduleTimeIsEarlierThanEndDateTimeException;
import org.black.phoneUtility.sms.schedule.service.exception.NoMessageException;
import org.black.phoneUtility.sms.schedule.service.exception.NoRecipientsException;
import org.black.phoneUtility.sms.schedule.service.exception.ScheduleTimeHasExpiredException;
import org.black.phoneUtility.sms.schedule.service.exception.SmsScheduleDoesNotExistException;

import android.content.ContentProviderOperation;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.RemoteException;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.CursorAdapter;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;

public class SmsScheduleListCursorAdapter extends CursorAdapter implements
		CompoundButton.OnCheckedChangeListener {
	private static final String LOG_TAG = SmsScheduleListCursorAdapter.class
			.getName();

	private Context context;
	private Map<Long, Boolean> selectionItems;
	private SmsScheduleService smsScheduleService;

	private class RecipientsAsyncTask extends AsyncTask<Long, Void, String> {
		private final WeakReference<TextView> recipientsDetailTextViewReference;

		public RecipientsAsyncTask(TextView textView) {
			recipientsDetailTextViewReference = new WeakReference<TextView>(
					textView);
		}

		@Override
		protected void onPostExecute(String result) {
			if (recipientsDetailTextViewReference != null && result != null) {
				final TextView textView = recipientsDetailTextViewReference
						.get();
				if (result != null) {
					textView.setText(result);
				}
			}

		}

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
		}

		@Override
		protected String doInBackground(Long... params) {
			Long smsScheduleId = params[0];

			Cursor cursor = null;
			try {
				cursor = context
						.getContentResolver()
						.query(SmsScheduleContract.SmsScheduleRecipients.CONTENT_URI,
								null,
								SmsScheduleContract.SmsScheduleRecipients.REFERENCE_SMS_SCHEDULE_ID
										+ " = ? ",
								new String[] { smsScheduleId.toString() },
								SmsScheduleContract.SmsScheduleRecipients.CREATION_DATE_TIME
										+ " ASC LIMIT 10");

				if (cursor != null && cursor.moveToFirst() == true) {
					boolean isAppended = false;
					String comma = context.getString(R.string.comma);
					StringBuilder resultBuilder = new StringBuilder();
					for (cursor.moveToFirst(); cursor.isAfterLast() == false; cursor
							.moveToNext()) {
						if (isAppended == false) {
							isAppended = true;
						} else {
							resultBuilder.append(comma);
						}
						int type = cursor
								.getInt(cursor
										.getColumnIndexOrThrow(SmsScheduleContract.SmsScheduleRecipients.TYPE));
						String phoneNumber = cursor
								.getString(cursor
										.getColumnIndexOrThrow(SmsScheduleContract.SmsScheduleRecipients.PHONE_NUMBER));
						switch (type) {
						case SmsScheduleContract.SmsScheduleRecipients.TYPE_USER_INPUT:
							resultBuilder.append(phoneNumber);
							break;
						case SmsScheduleContract.SmsScheduleRecipients.TYPE_CHOOSE_FROM_CONTACT:
						case SmsScheduleContract.SmsScheduleRecipients.TYPE_CHOOSE_FROM_CONTACT_GROUP:
							resultBuilder
									.append(context
											.getString(
													R.string.sms_schedule_list_row_recipient_name_with_phoneNumber,
													cursor.getString(cursor
															.getColumnIndexOrThrow(SmsScheduleContract.SmsScheduleRecipients.NAME)),
													cursor.getString(cursor
															.getColumnIndexOrThrow(SmsScheduleContract.SmsScheduleRecipients.PHONE_NUMBER))));
							break;
						default:
							Log.e(LOG_TAG, "Unknown type: " + type);
							break;
						}
					}
					return resultBuilder.toString();
				}
			} catch (Throwable th) {
				Log.e(LOG_TAG, "Query recipient fail!", th);
			} finally {
				if (cursor != null) {
					try {
						cursor.close();
					} catch (Throwable throwable) {
						Log.e(LOG_TAG, "Fail to close cursor", throwable);
					}
				}
			}
			return context
					.getString(R.string.sms_schedule_list_row_no_recipients);
		}
	}

	final static class ViewHolder {
		TextView subjectTextView;
		Switch activatedSwitch;

		TextView nextTextView;
		TextView recipientsTextView;
		TextView messageTextView;
	}

	public SmsScheduleListCursorAdapter(Context context, Cursor c, int flags) {
		super(context, c, flags);
		this.context = context;
		this.selectionItems = new HashMap<Long, Boolean>();
		this.smsScheduleService = new SmsScheduleService(this.context);
	}

	public void addSelection(int position, boolean checked) {
		this.selectionItems.put(getItemId(position), checked);
		this.notifyDataSetChanged();
	}

	public void removeSelection(int position) {
		this.selectionItems.remove(getItemId(position));
		this.notifyDataSetChanged();
	}

	public void removeSelections() {
		List<Long> smsScheduleIds = new ArrayList<Long>();
		Set<Long> keys = this.selectionItems.keySet();
		for (Long key : keys) {
			boolean checked = this.selectionItems.get(key);
			if (checked == true) {
				smsScheduleIds.add(key);
			}
		}

		if (smsScheduleIds.size() > 0) {
			ArrayList<ContentProviderOperation> contentProviderOperations = new ArrayList<ContentProviderOperation>();
			for (Long smsScheduleId : smsScheduleIds) {
				ContentProviderOperation.Builder builder = ContentProviderOperation
						.newDelete(SmsScheduleContract.SmsSchedules.CONTENT_URI)
						.withSelection(
								SmsScheduleContract.SmsSchedules._ID + " = ?",
								new String[] { String.valueOf(smsScheduleId) });
				contentProviderOperations.add(builder.build());
			}
			try {
				this.context.getContentResolver().applyBatch(
						SmsScheduleContract.AUTHORITY,
						contentProviderOperations);
				Log.i(LOG_TAG, "Delete sms schedule successfully!");
			} catch (RemoteException e) {
				Log.e(LOG_TAG, "RemoteException", e);
			} catch (OperationApplicationException e) {
				Log.e(LOG_TAG, "OperationApplicationException", e);
			}
		}

		this.notifyDataSetChanged();
	}

	public void copy() {
		try {
			Set<Long> keys = this.selectionItems.keySet();
			for (Long key : keys) {
				boolean checked = this.selectionItems.get(key);
				if (checked == true) {
					this.smsScheduleService.copy(key);
					break;
				}
			}
		} catch (RemoteException e) {
			Log.e(LOG_TAG, "RemoteException", e);
		} catch (OperationApplicationException e) {
			Log.e(LOG_TAG, "OperationApplicationException", e);
		}
	}

	public void clearSelection() {
		this.selectionItems.clear();
		this.notifyDataSetChanged();
	}

	public boolean isPositionChecked(int position) {
		Boolean result = this.selectionItems.get(position);
		return result == null ? false : result;
	}

	@Override
	public void bindView(View view, Context context, Cursor cursor) {
		ViewHolder viewHolder = (ViewHolder) view.getTag();
		long id = cursor.getLong(cursor
				.getColumnIndexOrThrow(SmsScheduleContract.SmsSchedules._ID));
		viewHolder.subjectTextView
				.setText(cursor.getString(cursor
						.getColumnIndexOrThrow(SmsScheduleContract.SmsSchedules.SUBJECT)));
		viewHolder.activatedSwitch.setOnCheckedChangeListener(null);
		viewHolder.activatedSwitch
				.setChecked(cursor.getInt(cursor
						.getColumnIndex(SmsScheduleContract.SmsSchedules.IS_ACTIVATED)) == 1 ? true
						: false);
		viewHolder.activatedSwitch.setTag(id);
		viewHolder.activatedSwitch.setOnCheckedChangeListener(this);
		viewHolder.messageTextView
				.setText(cursor.getString(cursor
						.getColumnIndexOrThrow(SmsScheduleContract.SmsSchedules.MESSAGE)));

		if (this.selectionItems.get(cursor.getLong(cursor
				.getColumnIndex(SmsScheduleContract.SmsSchedules._ID))) != null
				&& this.selectionItems.get(cursor.getLong(cursor
						.getColumnIndex(SmsScheduleContract.SmsSchedules._ID))) == true) {
			view.setBackgroundColor(this.context.getResources().getColor(
					android.R.color.holo_blue_light));
		} else {
			view.setBackground(this.context.getResources().getDrawable(
					android.R.drawable.list_selector_background));
		}
		if (cursor
				.isNull(cursor
						.getColumnIndexOrThrow(SmsScheduleContract.SmsSchedules.NEXT_SCHEDULE_DATE_TIME)) == false) {
			Date nextSchedule = new Date(
					cursor.getLong(cursor
							.getColumnIndexOrThrow(SmsScheduleContract.SmsSchedules.NEXT_SCHEDULE_DATE_TIME)));
			viewHolder.nextTextView.setText(DateFormat.getDateFormat(
					this.context).format(nextSchedule)
					+ " "
					+ DateFormat.getTimeFormat(this.context).format(
							nextSchedule));
		}
		new RecipientsAsyncTask(viewHolder.recipientsTextView).execute(id);
	}

	@Override
	public View newView(Context context, Cursor cursor, ViewGroup parent) {
		View result = LayoutInflater.from(context).inflate(
				R.layout.sms_schedule_list_row, parent, false);
		ViewHolder viewHolder = new ViewHolder();
		viewHolder.subjectTextView = (TextView) result
				.findViewById(R.id.smsScheduleListRowSubjectTextView);
		viewHolder.activatedSwitch = (Switch) result
				.findViewById(R.id.smsScheduleListRowActivatedSwitch);
		viewHolder.nextTextView = (TextView) result
				.findViewById(R.id.smsScheduleListRowNextDetailTextView);
		viewHolder.recipientsTextView = (TextView) result
				.findViewById(R.id.smsScheduleListRowRecipientsDetailTextView);
		viewHolder.messageTextView = (TextView) result
				.findViewById(R.id.smsScheduleListRowMessageDetailTextView);

		result.setTag(viewHolder);
		return result;
	}

	@Override
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
		long id = (Long) buttonView.getTag();

		String errorMessage = null;
		boolean switchStatus = false;
		try {
			switchStatus = this.smsScheduleService.switchActivatedStatus(id);
		} catch (NoMessageException e) {
			errorMessage = this.context
					.getString(R.string.sms_schedule_error_no_message);
		} catch (NoRecipientsException e) {
			errorMessage = this.context
					.getString(R.string.sms_schedule_error_no_recipient);
		} catch (ScheduleTimeHasExpiredException e) {
			errorMessage = this.context
					.getString(R.string.sms_schedule_error_schedule_has_expired);
		} catch (SmsScheduleDoesNotExistException e) {
			errorMessage = this.context
					.getString(R.string.sms_schedule_error_schedule_does_not_exist);
		} catch (EndDateTimeHasExpiredException e) {
			errorMessage = this.context
					.getString(R.string.sms_schedule_error_end_time_has_expired);
		} catch (NextScheduleTimeIsEarlierThanEndDateTimeException e) {
			errorMessage = this.context
					.getString(R.string.sms_schedule_error_next_schedule_date_time_is_earlier_than_end_time);
		}

		buttonView.setChecked(switchStatus);

		if (TextUtils.isEmpty(errorMessage) == false) {
			Toast.makeText(context, errorMessage, Toast.LENGTH_SHORT).show();
		}

	}
}
